在看完 jsonb 的 Index 之後,今天要來看的是 Full Text Search 了。全文搜尋也是實務上可能會碰到的問題,假如要搜尋的資料很多的話,要如何設定 Index 加快全文搜尋的速度呢?GIN & GiST 這兩種 Index 都能在全文搜尋時使用,但是這兩者之間有何差別?要如何選擇?
GIN 的全名為 Generalized Inverted Index,如果有使用過 ElasticSearch 的話就會知道「Inverted Index」的概念。想像它像一本書的索引,它將每個「詞彙」與所有包含這個詞彙的「頁碼」關聯起來。所以想要查詢某一個「詞彙」在哪裏有出現,就可以直接找到相對應的位置。
GiST 的全名為 Generalized Search Tree,是一種平衡樹,能夠處理更廣泛的資料型別和查詢類型,特別是那些涉及幾何、範圍和重疊關係的查詢(在之後的章節還會再看到它)。
其實在官方文件內就有針對 GIN vs GiST 在全文搜尋的比較:
從上述的特性可以得知,如果資料會是需要常常變動的話,GiST 會比較適合,因為 update / insert 速度較快。
另外官方文件也有給一個建議是,如果資料中的總詞彙數(unique lexemes)的話,會建議使用 GIN 搜尋讓效能加快,但也要注意 update / insert 速度會變慢,所以適合靜態資料。
As a rule of thumb, GIN indexes are best for static data because lookups are faster.
For dynamic data, GiST indexes are faster to update. Specifically, GiST indexes are very good for dynamic data and fast if the number of unique words (lexemes) is under 100,000, while GIN indexes will handle 100,000+ lexemes better but are slower to update.
接下來就來觀察這兩種 Index 在全文搜尋的差別吧!
CREATE TABLE articles (
id SERIAL PRIMARY KEY,
content TEXT,
);
import psycopg2
from faker import Faker
import json
import random
fake = Faker()
conn = psycopg2.connect(dbname="", user="", password="")
cur = conn.cursor()
insert_query = "INSERT INTO articles (content) VALUES (%s)"
data = [(fake.paragraph(nb_sentences=5),) for _ in range(1, 30001)]
cur.executemany(insert_query, data)
conn.commit()
cur.close()
conn.close()
EXPLAIN ANALYZE
SELECT * FROM articles
WHERE to_tsvector('english', content) @@ to_tsquery('help');
接下來就來看看使用 GIN 之後的差別!
CREATE INDEX idx_articles_content_gin ON articles
USING GIN(to_tsvector('english', content));
GIN
從原本 441ms 變成 1ms 了!速度相差非常多。那如果是用 GiST呢?
GiST
CREATE INDEX idx_articles_content_gist ON articles
USING GiST(to_tsvector('english', content));
從 441ms 變成 31ms,雖然沒有像 GIN 相差那麼多,但還是加快了不少。
因為官方文件有提到字數會影響到使用 GIN & GiST,所以想說把資料增加到 60000 看看,是不是兩者之間的差別會變大?
GIN
GiST
Rows | GIN | GiST |
---|---|---|
30000 | 1 ms | 31 ms |
60000 | 3 ms | 47 ms |
果然在資料量變多之後,GIN 和 GiST 的速度差距變得比較大了。不過除了這兩種用法之外,PostgreSQL 其實還提供另外一個 extension,可以搭配 GIN 和 GiST 加快全文搜索,明天就來看看這個特別的 extension 又有什麼特別之處吧。
Index | GIN | GiST |
---|---|---|
查詢速度 | 較快 | 較慢 |
update / insert | 較慢 | 較快 |
大小 | 較大 | 較小 |
適合資料類型 | 靜態(變動較少) | 動態(變動較多) |
總詞彙數 > 100,000 | 較快 | 較慢 |
https://www.postgresql.org/docs/9.1/textsearch-indexes.html